package com.welson.restfultoolx.service;

import com.intellij.openapi.components.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 缓存管理器服务实现
 * 提供高性能的LRU内存缓存
 */
@Service
public final class CacheManagerService implements CacheManager {
    
    private static final long DEFAULT_MAX_SIZE = 1000;
    private static final long DEFAULT_TTL_MINUTES = 30;
    
    private final Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
    private final Map<String, Long> accessOrder = new ConcurrentHashMap<>();
    private final AtomicLong accessCounter = new AtomicLong(0);
    private final CacheStatsImpl stats = new CacheStatsImpl();
    
    private volatile long maxSize = DEFAULT_MAX_SIZE;
    
    /**
     * 缓存项内部类
     */
    private static class CacheEntry {
        private final Object value;
        private final long createTime;
        private final long expireTime;
        
        public CacheEntry(Object value, long ttlMillis) {
            this.value = value;
            this.createTime = System.currentTimeMillis();
            this.expireTime = ttlMillis > 0 ? createTime + ttlMillis : Long.MAX_VALUE;
        }
        
        public Object getValue() {
            return value;
        }
        
        public boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }
        
        public long getCreateTime() {
            return createTime;
        }
    }
    
    /**
     * 缓存统计实现类
     */
    private static class CacheStatsImpl implements CacheStats {
        private final AtomicLong hitCount = new AtomicLong(0);
        private final AtomicLong missCount = new AtomicLong(0);
        private final AtomicLong evictionCount = new AtomicLong(0);
        private final AtomicLong loadCount = new AtomicLong(0);
        private final AtomicLong totalLoadTime = new AtomicLong(0);
        
        @Override
        public long getHitCount() {
            return hitCount.get();
        }
        
        @Override
        public long getMissCount() {
            return missCount.get();
        }
        
        @Override
        public double getHitRate() {
            long hits = hitCount.get();
            long total = hits + missCount.get();
            return total == 0 ? 0.0 : (double) hits / total;
        }
        
        @Override
        public long getEvictionCount() {
            return evictionCount.get();
        }
        
        @Override
        public long getLoadCount() {
            return loadCount.get();
        }
        
        @Override
        public double getAverageLoadTime() {
            long loads = loadCount.get();
            return loads == 0 ? 0.0 : (double) totalLoadTime.get() / loads;
        }
        
        public void recordHit() {
            hitCount.incrementAndGet();
        }
        
        public void recordMiss() {
            missCount.incrementAndGet();
        }
        
        public void recordEviction() {
            evictionCount.incrementAndGet();
        }
        
        public void recordLoad(long loadTime) {
            loadCount.incrementAndGet();
            totalLoadTime.addAndGet(loadTime);
        }
    }
    
    @Override
    public void put(String key, Object value) {
        put(key, value, DEFAULT_TTL_MINUTES, TimeUnit.MINUTES);
    }
    
    @Override
    public void put(String key, Object value, long ttl, TimeUnit timeUnit) {
        if (key == null || value == null) {
            return;
        }
        
        long ttlMillis = timeUnit.toMillis(ttl);
        CacheEntry entry = new CacheEntry(value, ttlMillis);
        
        cache.put(key, entry);
        accessOrder.put(key, accessCounter.incrementAndGet());
        
        // 检查缓存大小限制
        if (cache.size() > maxSize) {
            evictLRU();
        }
        
        stats.recordLoad(0); // 记录加载（这里是直接存储，所以时间为0）
    }
    
    @Override
    public <T> Optional<T> get(String key, Class<T> type) {
        if (key == null) {
            stats.recordMiss();
            return Optional.empty();
        }
        
        CacheEntry entry = cache.get(key);
        if (entry == null) {
            stats.recordMiss();
            return Optional.empty();
        }
        
        // 检查是否过期
        if (entry.isExpired()) {
            cache.remove(key);
            accessOrder.remove(key);
            stats.recordMiss();
            return Optional.empty();
        }
        
        // 更新访问顺序
        accessOrder.put(key, accessCounter.incrementAndGet());
        stats.recordHit();
        
        try {
            return Optional.of(type.cast(entry.getValue()));
        } catch (ClassCastException e) {
            // 类型不匹配，移除缓存项
            cache.remove(key);
            accessOrder.remove(key);
            stats.recordMiss();
            return Optional.empty();
        }
    }
    
    @Override
    public <T> T get(String key, Class<T> type, T defaultValue) {
        return get(key, type).orElse(defaultValue);
    }
    
    @Override
    public boolean containsKey(String key) {
        if (key == null) {
            return false;
        }
        
        CacheEntry entry = cache.get(key);
        if (entry == null) {
            return false;
        }
        
        // 检查是否过期
        if (entry.isExpired()) {
            cache.remove(key);
            accessOrder.remove(key);
            return false;
        }
        
        return true;
    }
    
    @Override
    public boolean remove(String key) {
        if (key == null) {
            return false;
        }
        
        boolean removed = cache.remove(key) != null;
        accessOrder.remove(key);
        return removed;
    }
    
    @Override
    public void invalidate(String key) {
        remove(key);
    }
    
    @Override
    public void clear() {
        cache.clear();
        accessOrder.clear();
        accessCounter.set(0);
    }
    
    @Override
    public long size() {
        // 清理过期项后返回实际大小
        cleanUp();
        return cache.size();
    }
    
    @Override
    public CacheStats getStats() {
        return stats;
    }
    
    @Override
    public void cleanUp() {
        List<String> expiredKeys = new ArrayList<>();
        
        for (Map.Entry<String, CacheEntry> entry : cache.entrySet()) {
            if (entry.getValue().isExpired()) {
                expiredKeys.add(entry.getKey());
            }
        }
        
        for (String key : expiredKeys) {
            cache.remove(key);
            accessOrder.remove(key);
        }
    }
    
    @Override
    public void setMaxSize(long maxSize) {
        this.maxSize = Math.max(1, maxSize);
        
        // 如果当前大小超过新的最大大小，进行清理
        while (cache.size() > this.maxSize) {
            evictLRU();
        }
    }
    
    /**
     * 驱逐最近最少使用的缓存项
     */
    private void evictLRU() {
        if (cache.isEmpty()) {
            return;
        }
        
        // 找到访问时间最早的键
        String lruKey = null;
        long minAccessTime = Long.MAX_VALUE;
        
        for (Map.Entry<String, Long> entry : accessOrder.entrySet()) {
            if (entry.getValue() < minAccessTime) {
                minAccessTime = entry.getValue();
                lruKey = entry.getKey();
            }
        }
        
        if (lruKey != null) {
            cache.remove(lruKey);
            accessOrder.remove(lruKey);
            stats.recordEviction();
        }
    }
    
    /**
     * 获取缓存使用情况的调试信息
     */
    public String getDebugInfo() {
        cleanUp();
        
        StringBuilder sb = new StringBuilder();
        sb.append("Cache Debug Info:\n");
        sb.append("Size: ").append(cache.size()).append("/").append(maxSize).append("\n");
        sb.append("Hit Rate: ").append(String.format("%.2f%%", stats.getHitRate() * 100)).append("\n");
        sb.append("Hits: ").append(stats.getHitCount()).append("\n");
        sb.append("Misses: ").append(stats.getMissCount()).append("\n");
        sb.append("Evictions: ").append(stats.getEvictionCount()).append("\n");
        
        return sb.toString();
    }
    
    /**
     * 获取指定前缀的所有缓存键
     */
    public Set<String> getKeysWithPrefix(String prefix) {
        if (prefix == null) {
            return Collections.emptySet();
        }
        
        Set<String> matchingKeys = new HashSet<>();
        for (String key : cache.keySet()) {
            if (key.startsWith(prefix)) {
                matchingKeys.add(key);
            }
        }
        
        return matchingKeys;
    }
    
    /**
     * 批量移除指定前缀的缓存项
     */
    public int removeWithPrefix(String prefix) {
        Set<String> keysToRemove = getKeysWithPrefix(prefix);
        for (String key : keysToRemove) {
            remove(key);
        }
        return keysToRemove.size();
    }
}